<template>
    <n-upload
        id="upload"
        v-model:file-list="fileList"
        list-type="image-card"
        :custom-request="customRequest"
        @finish="onFinish"
        @remove="onRemove"
        :max="single ? 1 : undefined"
        :multiple="!single"
        draggable
    />
</template>

<script lang="ts" setup>
import { UPLOAD } from '@/config/api'
import { IUpload } from '@/types/global'
import axios from 'axios'
import {
    UploadCustomRequestOptions,
    UploadFileInfo,
    useMessage
} from 'naive-ui'
import { ref, watch, onMounted, onUnmounted } from 'vue'
import Sortable from 'sortablejs'
import { UploadImageProps } from '../types'

const message = useMessage()
const emits = defineEmits(['update:value'])
const props = withDefaults(defineProps<UploadImageProps>(), {
    single: true,
    value: ''
})

const fileList = ref<UploadFileInfo[]>([])

const onFinish = ({ file }: { file: UploadFileInfo }) => {
    const updatedValue = props.single
        ? file.url
        : [...(props.value as string[]), file.url]
    emits('update:value', updatedValue)
}

const onRemove = (options: { file: UploadFileInfo }) => {
    const updatedValue = props.single
        ? ''
        : (props.value as string[]).filter((url) => url !== options.file.url)
    emits('update:value', updatedValue)
}

const handleProps = () => {
    const urls = props.single
        ? props.value
            ? [props.value as string]
            : []
        : props.value
          ? (props.value as string[])
          : []
    fileList.value = urls.map((url, index) => ({
        id: `id_${index}`,
        name: `file_${index}`,
        status: 'finished',
        url
    }))
}

const unwatch = watch(() => props.value, handleProps)

onMounted(() => {
    handleProps()
    if (!props.single) setSortable()
})

onUnmounted(() => {
    unwatch()
    fileList.value = []
})

const customRequest = async ({
    file,
    data,
    onFinish,
    onError,
    onProgress
}: UploadCustomRequestOptions) => {
    const formData = new FormData()
    Object.entries(data || {}).forEach(([key, value]) => {
        formData.append(key, value)
    })
    formData.append('file', file.file as File)

    try {
        const res = await axios.post<any, IUpload>(UPLOAD, formData, {
            onUploadProgress: (e) => {
                onProgress({ percent: Math.ceil((e.progress || 0) * 100) })
            }
        })

        file.url = res.src
        onFinish()
    } catch (err) {
        message.error((err as Error).message)
        onError()
    }
}

const setSortable = () => {
    const el = document.getElementsByClassName(
        'n-upload-file-list'
    )[0] as HTMLElement
    new Sortable(el, {
        draggable: '.n-upload-file',
        ghostClass: 'blue-background-class',
        animation: 150,
        onEnd: ({ oldIndex, newIndex }) => {
            const item = fileList.value.splice(oldIndex!, 1)[0]
            fileList.value.splice(newIndex!, 0, item)
            emits(
                'update:value',
                fileList.value.map((item) => item.url)
            )
        }
    })
}
</script>
